package dm.ast.model.gen.factory;

import test.utility.Randomly;

import java.util.ArrayList;
import java.util.List;

/**
 * @author scy
 * @date 2024/4/16
 * bool表达式的复杂度模板设置
 */
public class BoolExpModelFactory extends BaseModelFactory{
    //根据宽度、深度，返回查询列模型
    public static ComplexityModel boolModels(int wid_t , int dep_t){
        List<ComplexityModel> models = new ArrayList<ComplexityModel>();

        //1、极值分配
        models.addAll(modelExtreme(wid_t , dep_t));

        //2、深度平均分配
        if(wid_t > estimateMinWidt(dep_t) && dep_t > 1){
            models.addAll(modelAverage(wid_t , dep_t));
        }

        return Randomly.fromList(models);
    }

    //极值分配
    public static List<ComplexityModel> modelExtreme(int wid_t , int dep_t){
        List<ComplexityModel> extreme = new ArrayList<ComplexityModel>();
        ComplexityModel model;

        //仅一个bool表达式
        model = new ComplexityModel(1);
        model.comps[0].wid_t = wid_t;
        model.comps[0].dep_t = dep_t;
        extreme.add(model);
        //尽可能多的bool表达式，随便选择一个bool表达式深度设为dep_t
        int maxDept_widt = setWidtByDept(dep_t);
        if(wid_t > maxDept_widt){
            model = new ComplexityModel((wid_t - maxDept_widt)/FactoryConstant.MIN_EXP_WIDT + 1);
            for (int i = 0; i < model.count; i++) {
                model.comps[i].wid_t = FactoryConstant.MIN_WIDT_COMP;
                model.comps[i].dep_t = 1;
            }
            int j = r.getInteger(0 , model.count);
            model.comps[j].dep_t = dep_t;
            model.comps[j].wid_t = maxDept_widt;
            extreme.add(model);
        }
        return extreme;
    }

    //深度平均分配
    public static List<ComplexityModel> modelAverage(int wid_t, int dep_t) {
        List<ComplexityModel> average = new ArrayList<ComplexityModel>();
        ComplexityModel model = new ComplexityModel(wid_t / FactoryConstant.MIN_WIDT_COMP + 1);
        //需要考虑多深度时wid的变化
        int tmp_widt_used = 0;
        int tmp_widt = 0;
        for (int i = 0; i < model.count; i++) {
            model.comps[i].dep_t = r.getInteger(1, dep_t + 1);
            tmp_widt = setWidtByDept(model.comps[i].dep_t);
            if(wid_t - tmp_widt_used > tmp_widt){

                model.comps[i].wid_t = r.getInteger(tmp_widt , wid_t + 1);
            }else {
                model.comps[i].wid_t = tmp_widt;
            }
            tmp_widt_used += model.comps[i].wid_t;
            if (tmp_widt_used >= wid_t) {  //宽度已经达到要求，那么终止
                model.count = i; //提前结束，原定的count数目需要根据实际情况修改
                break;
            }

        }
        average.add(model);
        return average;
    }

    //logic表达式模板
    //例如1>1，仅需要分割为2个表达式
    public static ComplexityModel logicModels(int wid_t , int dep_t){
        List<ComplexityModel> models = new ArrayList<ComplexityModel>();
        models.add(defaultModel(wid_t - 1 , dep_t , 2));
        return Randomly.fromList(models);
    }

    //between表达式模板
    //例如 2 between 1 and 4，仅需要分割为3个表达式
    public static ComplexityModel betweenModels(int wid_t , int dep_t ){
        List<ComplexityModel> models = new ArrayList<ComplexityModel>();
        models.add(defaultModel(wid_t - 1 , dep_t , 3));
        return Randomly.fromList(models);
    }

    //in表达式模板
    //例如 1 in (1 ,2 ,3)，需要先确定in 表达式的个数，然后再进行划分
    public static ComplexityModel inModels(int wid_t , int dep_t){
        List<ComplexityModel> models = new ArrayList<ComplexityModel>();
        int fields = 0;
        int left = 0; // in的左边操作数的表达式数目

        //生成一列的比例大于50%
        if(Randomly.getBoolean()){
            left = r.getInteger(1 , FactoryConstant.MAX_INLEFTNUM + 1);
        }else {
            left = 1;
        }

        if(dep_t == 1){ //深度为1
            fields = wid_t - 1;
        }else {
            fields = wid_t - estimateMinWidt(dep_t) - 1;
        }

        if(fields < 2){
            fields = 2; //表达式的个数至少为2个
        }

        //left不能大于fields的一半
        if(left * 2 > fields){
            left = fields / 2;
        }

        ComplexityModel models1 = defaultModel(wid_t - 1 , dep_t , fields);

        models1.setInLeft(left);
        models.add(models1);

        return Randomly.fromList(models);
    }
}
